// Process Management Tools Implementation

import { spawn, ChildProcess } from 'child_process';
import {
    ToolHandler,
    ToolResult,
    ToolExecutionContext,
    ValidationResult
} from '../core/interfaces';

interface ProcessInfo {
    id: number;
    process: ChildProcess;
    output: string;
    error: string;
    startTime: number;
    completed: boolean;
    exitCode?: number;
}

/**
 * 进程管理器 - 单例模式
 */
class ProcessManager {
    private static instance: ProcessManager;
    private processes: Map<number, ProcessInfo> = new Map();
    private processCounter: number = 0;

    static getInstance(): ProcessManager {
        if (!ProcessManager.instance) {
            ProcessManager.instance = new ProcessManager();
        }
        return ProcessManager.instance;
    }

    createProcess(command: string, cwd: string, wait: boolean): ProcessInfo {
        const terminalId = ++this.processCounter;

        // 根据操作系统选择shell
        const isWindows = process.platform === 'win32';
        const shell = isWindows ? 'cmd' : 'bash';
        const shellArgs = isWindows ? ['/c', command] : ['-c', command];

        const childProcess = spawn(shell, shellArgs, {
            cwd: cwd,
            stdio: ['pipe', 'pipe', 'pipe']
        });

        const processInfo: ProcessInfo = {
            id: terminalId,
            process: childProcess,
            output: '',
            error: '',
            startTime: Date.now(),
            completed: false
        };

        // 收集输出
        childProcess.stdout?.on('data', (data) => {
            processInfo.output += data.toString();
        });

        childProcess.stderr?.on('data', (data) => {
            processInfo.error += data.toString();
        });

        childProcess.on('close', (code) => {
            processInfo.completed = true;
            processInfo.exitCode = code || 0;
        });

        this.processes.set(terminalId, processInfo);
        return processInfo;
    }

    getProcess(terminalId: number): ProcessInfo | null {
        return this.processes.get(terminalId) || null;
    }

    killProcess(terminalId: number): boolean {
        const processInfo = this.processes.get(terminalId);
        if (processInfo && !processInfo.completed) {
            processInfo.process.kill();
            processInfo.completed = true;
            return true;
        }
        return false;
    }

    async waitForProcess(terminalId: number, maxWaitSeconds: number): Promise<ProcessInfo> {
        const processInfo = this.processes.get(terminalId);
        if (!processInfo) {
            throw new Error(`Process with terminal ID ${terminalId} not found`);
        }

        if (processInfo.completed) {
            return processInfo;
        }

        return new Promise((resolve, reject) => {
            const timeout = setTimeout(() => {
                reject(new Error(`Process timeout after ${maxWaitSeconds} seconds`));
            }, maxWaitSeconds * 1000);

            processInfo.process.on('close', () => {
                clearTimeout(timeout);
                resolve(processInfo);
            });
        });
    }

    writeToProcess(terminalId: number, input: string): boolean {
        const processInfo = this.processes.get(terminalId);
        if (processInfo && !processInfo.completed && processInfo.process.stdin) {
            processInfo.process.stdin.write(input);
            return true;
        }
        return false;
    }

    getAllProcesses(): ProcessInfo[] {
        return Array.from(this.processes.values());
    }

    cleanup(): void {
        for (const processInfo of this.processes.values()) {
            if (!processInfo.completed) {
                processInfo.process.kill();
            }
        }
        this.processes.clear();
    }
}

/**
 * 启动进程工具
 */
export class LaunchProcessHandler implements ToolHandler {
    private processManager = ProcessManager.getInstance();

    async execute(parameters: Record<string, any>, context: ToolExecutionContext): Promise<ToolResult> {
        const { command, wait, max_wait_seconds, cwd } = parameters;

        try {
            const processInfo = this.processManager.createProcess(command, cwd, wait);

            if (wait) {
                const result = await this.processManager.waitForProcess(processInfo.id, max_wait_seconds);
                return {
                    success: true,
                    data: {
                        terminal_id: result.id,
                        output: result.output,
                        error: result.error,
                        exit_code: result.exitCode,
                        completed: result.completed,
                        execution_time: Date.now() - result.startTime
                    }
                };
            } else {
                return {
                    success: true,
                    data: {
                        terminal_id: processInfo.id,
                        message: 'Process started in background',
                        started_at: new Date(processInfo.startTime).toISOString()
                    }
                };
            }
        } catch (error) {
            throw new Error(`Failed to launch process: ${error instanceof Error ? error.message : `${error}`}`);
        }
    }

    validate(parameters: Record<string, any>): ValidationResult {
        const errors: string[] = [];

        if (!parameters.command || typeof parameters.command !== 'string') {
            errors.push('command parameter is required and must be a string');
        }

        if (typeof parameters.wait !== 'boolean') {
            errors.push('wait parameter is required and must be a boolean');
        }

        if (typeof parameters.max_wait_seconds !== 'number') {
            errors.push('max_wait_seconds parameter is required and must be a number');
        }

        if (!parameters.cwd || typeof parameters.cwd !== 'string') {
            errors.push('cwd parameter is required and must be a string');
        }

        return {
            isValid: errors.length === 0,
            errors: errors
        };
    }
}

/**
 * 终止进程工具
 */
export class KillProcessHandler implements ToolHandler {
    private processManager = ProcessManager.getInstance();

    async execute(parameters: Record<string, any>, context: ToolExecutionContext): Promise<ToolResult> {
        const { terminal_id } = parameters;

        try {
            const success = this.processManager.killProcess(terminal_id);

            if (success) {
                return {
                    success: true,
                    data: {
                        terminal_id: terminal_id,
                        message: 'Process killed successfully'
                    }
                };
            } else {
                return {
                    success: false,
                    error: {
                        code: 'PROCESS_NOT_FOUND',
                        message: `Process with terminal ID ${terminal_id} not found or already completed`
                    }
                };
            }
        } catch (error) {
            throw new Error(`Failed to kill process: ${error instanceof Error ? error.message : `${error}`}`);
        }
    }

    validate(parameters: Record<string, any>): ValidationResult {
        const errors: string[] = [];

        if (typeof parameters.terminal_id !== 'number') {
            errors.push('terminal_id parameter is required and must be a number');
        }

        return {
            isValid: errors.length === 0,
            errors: errors
        };
    }
}

/**
 * 读取进程输出工具
 */
export class ReadProcessHandler implements ToolHandler {
    private processManager = ProcessManager.getInstance();

    async execute(parameters: Record<string, any>, context: ToolExecutionContext): Promise<ToolResult> {
        const { terminal_id, wait, max_wait_seconds } = parameters;

        try {
            let processInfo = this.processManager.getProcess(terminal_id);

            if (!processInfo) {
                throw new Error(`Process with terminal ID ${terminal_id} not found`);
            }

            if (wait && !processInfo.completed) {
                processInfo = await this.processManager.waitForProcess(terminal_id, max_wait_seconds);
            }

            return {
                success: true,
                data: {
                    terminal_id: terminal_id,
                    output: processInfo.output,
                    error: processInfo.error,
                    completed: processInfo.completed,
                    exit_code: processInfo.exitCode,
                    execution_time: Date.now() - processInfo.startTime
                }
            };
        } catch (error) {
            throw new Error(`Failed to read process output: ${error instanceof Error ? error.message : `${error}`}`);
        }
    }

    validate(parameters: Record<string, any>): ValidationResult {
        const errors: string[] = [];

        if (typeof parameters.terminal_id !== 'number') {
            errors.push('terminal_id parameter is required and must be a number');
        }

        if (typeof parameters.wait !== 'boolean') {
            errors.push('wait parameter is required and must be a boolean');
        }

        if (typeof parameters.max_wait_seconds !== 'number') {
            errors.push('max_wait_seconds parameter is required and must be a number');
        }

        return {
            isValid: errors.length === 0,
            errors: errors
        };
    }
}

/**
 * 向进程写入输入工具
 */
export class WriteProcessHandler implements ToolHandler {
    private processManager = ProcessManager.getInstance();

    async execute(parameters: Record<string, any>, context: ToolExecutionContext): Promise<ToolResult> {
        const { terminal_id, input_text } = parameters;

        try {
            const success = this.processManager.writeToProcess(terminal_id, input_text);

            if (success) {
                return {
                    success: true,
                    data: {
                        terminal_id: terminal_id,
                        message: 'Input written to process successfully',
                        input_length: input_text.length
                    }
                };
            } else {
                return {
                    success: false,
                    error: {
                        code: 'PROCESS_NOT_WRITABLE',
                        message: `Process with terminal ID ${terminal_id} not found or not writable`
                    }
                };
            }
        } catch (error) {
            throw new Error(`Failed to write to process: ${error instanceof Error ? error.message : `${error}`}`);
        }
    }

    validate(parameters: Record<string, any>): ValidationResult {
        const errors: string[] = [];

        if (typeof parameters.terminal_id !== 'number') {
            errors.push('terminal_id parameter is required and must be a number');
        }

        if (!parameters.input_text || typeof parameters.input_text !== 'string') {
            errors.push('input_text parameter is required and must be a string');
        }

        return {
            isValid: errors.length === 0,
            errors: errors
        };
    }
}

/**
 * 列出所有进程工具
 */
export class ListProcessesHandler implements ToolHandler {
    private processManager = ProcessManager.getInstance();

    async execute(parameters: Record<string, any>, context: ToolExecutionContext): Promise<ToolResult> {
        try {
            const processes = this.processManager.getAllProcesses();

            const processData = processes.map(proc => ({
                terminal_id: proc.id,
                completed: proc.completed,
                exit_code: proc.exitCode,
                start_time: new Date(proc.startTime).toISOString(),
                execution_time: Date.now() - proc.startTime,
                has_output: proc.output.length > 0,
                has_error: proc.error.length > 0
            }));

            return {
                success: true,
                data: {
                    processes: processData,
                    total_count: processData.length
                }
            };
        } catch (error) {
            throw new Error(`Failed to list processes: ${error instanceof Error ? error.message : `${error}`}`);
        }
    }

    validate(parameters: Record<string, any>): ValidationResult {
        // 此工具不需要参数
        return {
            isValid: true,
            errors: []
        };
    }
}
